
package com.yadong.smarthome2.messageparser;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.yadong.smarthome2.device.Device;
import com.yadong.smarthome2.protocol2.ALog;
import com.yadong.smarthome2.protocol2.RequestProtocol.Request;
import com.yadong.smarthome2.protocol2.ResultProtocol.Result;

public class RequestManager extends Thread {
    private static final int REQUEST_TIME_OUT = 5 * 1000;
    private Map<Device, List<Request>> mRequests = new HashMap<Device, List<Request>>();
    private RequestTimeoutListener mRequestTimeoutListener;

    public interface RequestTimeoutListener {
        public void onRequestTimeOut(Device device, Request request);
    }

    public RequestManager() {
    }

    public void setRequestTimeoutListener(RequestTimeoutListener listener) {
        this.mRequestTimeoutListener = listener;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (mRequests) {
                for (Device deviceKey : mRequests.keySet()) {
                    List<Request> requests = (List<Request>) 
                            ((ArrayList<Request>)mRequests.get(deviceKey)).clone();
                    for (Request request : requests) {
                        try {
                            long time = request.getTime();
                            long currentTime = System.currentTimeMillis();
                            if (currentTime - time > REQUEST_TIME_OUT) {
                                if (mRequestTimeoutListener != null) {
                                    mRequestTimeoutListener.onRequestTimeOut(deviceKey,
                                            request);
                                }
                                mRequests.get(deviceKey).remove(request);
                            }
                        } catch (NumberFormatException e) {
                            ALog.loge(this, "error request tag :"
                                    + request.getTag() + " for device:"
                                    + deviceKey.getDeviceDescription() + " remove it");
                            mRequests.get(deviceKey).remove(request);
                        }
                    }
                }
            }
            try {
                Thread.sleep(REQUEST_TIME_OUT * 2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void removeRequest(Device device, Request request) {
        synchronized (mRequests) {
            List<Request> requests = mRequests.get(device);
            if (requests != null) {
                requests.remove(request);
            }
        }
    }

    public void addRequest(Device device, Request request) {
        synchronized (mRequests) {
            List<Request> requests = mRequests.get(device);
            if (requests == null) {
                requests = new ArrayList<Request>();
                mRequests.put(device, requests);
            }
            requests.add(request);
        }
    }

    public boolean hasNoReponseRquest(Device device) {
        synchronized (mRequests) {
            return mRequests.get(device) == null || mRequests.get(device).size() > 0;
        }
    }

    public boolean hasParidedRequest(Device device, Result result) {
        return pairRequest(device, result, false);
    }

    public boolean pairRequest(Device device, Result result) {
        return pairRequest(device, result, true);
    }

    private boolean pairRequest(Device device, Result result, boolean remove) {
        synchronized (mRequests) {
            List<Request> requests = mRequests.get(device);
            if (requests == null || requests.size() <= 0) {
                return false;
            }
            for (Request request : requests) {
                if (result.getTag().equals(request.getTag())
                        && result.getTime() == request.getTime()) {
                    if (remove) {
                        requests.remove(request);
                    }
                    return true;
                }
            }
            return false;
        }
    }
}
